/*
File:		TankBot.cpp
Author:		Ben Feldmann
Purpose:	Class to manage game TankBot enemies
*/

#include "TankBot.h"
#include "SGD Wrappers/CSGD_TextureManager.h"
#include "SGD Wrappers/CSGD_Direct3D.h"
#include "SGD Wrappers/CSGD_XAudio2.h"
#include "Event.h"
#include "EventSystem.h"
#include "MessageSystem.h"
#include "DestroyEntityMessage.h"
#include "CreateProjectileMessage.h"
#include "CreatePickUpMessage.h"
#include "GamePlayState.h"
#include "Tile.h"
#include "Game.h"


TankBot::TankBot() : target(nullptr)
{
	SetHealth(300.0f);
	SetDifficulty(10);
	SetWidth(64);
	SetHeight(64);
	SetAttackTimer(0.0f);
	SetSpeed(16);
	attackPlace = 1;

	int randParts = rand() % 10 + 5;
	SetMetal(randParts);
	SetCircuitry(randParts);
	damage = 10.0f;
	inRange = false;

	SetDirection(0);
	BackAwayTimer = 0.0f;

	SetPrevX(GetX()); 
	SetPrevY(GetY());
	SetCollided(false);

	AttackSound = CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/Push_Sound.wav"));
	WalkSound = CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/Tank_Walk.wav"));
	DeathSound = CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/Death_Sound.wav"));
	FireSound = CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/Tank_Fire.wav"));

	EventSystem::GetInstance()->RegisterClient("target_hit", this);

	maxHealth = (int)GetHealth();
}

TankBot::~TankBot() 
{	
	EventSystem::GetInstance()->UnregisterClientAll(this);

	if( target )
		target->Release();
}

void TankBot::Update(float elapsed) 
{
	int camx = GamePlayState::GetInstance()->GetCamX();
	int camy = GamePlayState::GetInstance()->GetCamY();
	if( GetX() > camx + 800 || GetX() + GetWidth() < camx || GetY() + GetHeight() < camy || GetY() > camy + 600 )
	{
		return;
	}

	// Update for enemy
	Enemy::Update(elapsed);

	// Health over max?
	if(GetHealth() > maxHealth)
		SetHealth((float)maxHealth);

	// If you have checked all attack places check again
	if(attackPlace > 4)
		attackPlace = 1;

	// Check if dead
	if(GetHealth() <= 0)
	{
		CreatePickUpMessage* msg1 = new CreatePickUpMessage(0, GetMetal(), GetVectorPos(), GetType());
		MessageSystem::GetInstance()->SendMsg(msg1);
		msg1 = nullptr;


		CreatePickUpMessage* msg2 = new CreatePickUpMessage(1, GetCircuitry(), GetVectorPos(), GetType());
		MessageSystem::GetInstance()->SendMsg(msg2);
		msg2 = nullptr;

		DestroyEntityMessage* msg = new DestroyEntityMessage(this);
		MessageSystem::GetInstance()->SendMsg(msg);
		msg = nullptr;

		CSGD_XAudio2::GetInstance()->SFXPlaySound(DeathSound);

		return;
	}

	if(disabled == true)
		return;

	if( target )
		target->Release();
	target = nullptr;

	// Get target player
	if(GamePlayState::GetInstance()->GetPlayer2() != nullptr)
	{
		float p1distance = -1, p2distance = -1;
		float p1x = -1, p2x = -1;
		float p1y = -1, p2y = -1;

		p1x = (GamePlayState::GetInstance()->GetPlayer()->GetX()-GetX())*(GamePlayState::GetInstance()->GetPlayer()->GetX()-GetX());
		p1y = (GamePlayState::GetInstance()->GetPlayer()->GetY()-GetY())*(GamePlayState::GetInstance()->GetPlayer()->GetY()-GetY());
		p1distance = sqrtf(p1x+p1y);

		p2x = (GamePlayState::GetInstance()->GetPlayer2()->GetX()-GetX())*(GamePlayState::GetInstance()->GetPlayer2()->GetX()-GetX());
		p2y = (GamePlayState::GetInstance()->GetPlayer2()->GetY()-GetY())*(GamePlayState::GetInstance()->GetPlayer2()->GetY()-GetY());
		p2distance = sqrtf(p2x+p2y);

		if(p1distance <= p2distance)
			target = GamePlayState::GetInstance()->GetPlayer();
		else
			target = GamePlayState::GetInstance()->GetPlayer2();
	}
	else
		target = GamePlayState::GetInstance()->GetPlayer();

	if( target )
		target->AddRef();
	else
		return;

	// CARDINAL
	if(target->GetY() <= GetY() && target->GetX() >= GetX()-64 && target->GetX() <= GetX()+64)
		SetDirection(3);
	else if(target->GetX() >= GetX() && target->GetY() >= GetY()-64 && target->GetY() <= GetY()+64)
		SetDirection(0);
	else if(target->GetY() > GetY() && target->GetX() >= GetX()-64 && target->GetX() <= GetX()+64)
		SetDirection(2);
	else if(target->GetX() < GetX() && target->GetY() >= GetY()-64 && target->GetY() <= GetY()+64)
		SetDirection(1);
	else
		SetDirection(-1);

	SetAttackTimer(GetAttackTimer()+(1.0f*elapsed));
	if(target->GetCamo() == false && GetAttackTimer() >= 1.0f && GetX() < GamePlayState::GetInstance()->GetCamX()+Game::GetInstance()->GetScreenWidth() && GetY() < GamePlayState::GetInstance()->GetCamY()+Game::GetInstance()->GetScreenHeight()
		&& GetX() > GamePlayState::GetInstance()->GetCamX() && GetY() > GamePlayState::GetInstance()->GetCamY() && GetDirection() != -1 && inRange == false)
	{
		Attack();
		SetAttackTimer(0.0f);
	}

	// Head toward's target
	if(target->GetCamo() == false && GetX() < GamePlayState::GetInstance()->GetCamX()+Game::GetInstance()->GetScreenWidth() && GetY() < GamePlayState::GetInstance()->GetCamY()+Game::GetInstance()->GetScreenHeight()
		&& GetX() > GamePlayState::GetInstance()->GetCamX() && GetY() > GamePlayState::GetInstance()->GetCamY() && GetCollided() == false && attackPlace == 1)
	{

		if(GetRect().left != target->GetRect().right-1 && target->GetRect().right-1 >= GetRect().left)
		{
			SetX(GetX()+(GetSpeed()*elapsed));
			SetDirection(0);
		}
		else if(GetRect().left != target->GetRect().right-1 && target->GetRect().right-1 <= GetRect().left)
		{
			SetX(GetX()-(GetSpeed()*elapsed));
			SetDirection(1);
		}

		else if(GetRect().top != target->GetRect().top && target->GetRect().top >= GetRect().top)
		{
			SetY(GetY()+(GetSpeed()*elapsed));
			SetDirection(2);
		}
		else if(GetRect().top != target->GetRect().top && target->GetRect().top <= GetRect().top)
		{
			SetY(GetY()-(GetSpeed()*elapsed));
			SetDirection(3);
		}
	}
	else if(target->GetCamo() == false && GetX() < GamePlayState::GetInstance()->GetCamX()+Game::GetInstance()->GetScreenWidth() && GetY() < GamePlayState::GetInstance()->GetCamY()+Game::GetInstance()->GetScreenHeight()
		&& GetX() > GamePlayState::GetInstance()->GetCamX() && GetY() > GamePlayState::GetInstance()->GetCamY() && GetCollided() == false && attackPlace == 2)
	{

		if(GetRect().right != target->GetRect().left+1 && target->GetRect().left+1 >= GetRect().right)
		{
			SetX(GetX()+(GetSpeed()*elapsed));
			SetDirection(0);
		}
		else if(GetRect().right != target->GetRect().left+1 && target->GetRect().left+1 <= GetRect().right)
		{
			SetX(GetX()-(GetSpeed()*elapsed));
			SetDirection(1);
		}

		else if(GetRect().top != target->GetRect().top && target->GetRect().top >= GetRect().top)
		{
			SetY(GetY()+(GetSpeed()*elapsed));
			SetDirection(2);
		}
		else if(GetRect().top != target->GetRect().top && target->GetRect().top <= GetRect().top)
		{
			SetY(GetY()-(GetSpeed()*elapsed));
			SetDirection(3);
		}
	}
	else if(target->GetCamo() == false && GetX() < GamePlayState::GetInstance()->GetCamX()+Game::GetInstance()->GetScreenWidth() && GetY() < GamePlayState::GetInstance()->GetCamY()+Game::GetInstance()->GetScreenHeight()
		&& GetX() > GamePlayState::GetInstance()->GetCamX() && GetY() > GamePlayState::GetInstance()->GetCamY() && GetCollided() == false && attackPlace == 3)
	{
		if(GetRect().bottom != target->GetRect().top+1 && target->GetRect().top+1 >= GetRect().bottom)
		{
			SetY(GetY()+(GetSpeed()*elapsed));
			SetDirection(2);
		}
		else if(GetRect().bottom != target->GetRect().top+1 && target->GetRect().top+1 <= GetRect().bottom)
		{
			SetY(GetY()-(GetSpeed()*elapsed));
			SetDirection(3);
		}

		else if(GetRect().right != target->GetRect().right && target->GetRect().right >= GetRect().right)
		{
			SetX(GetX()+(GetSpeed()*elapsed));
			SetDirection(0);
		}
		else if(GetRect().right != target->GetRect().right && target->GetRect().right <= GetRect().right)
		{
			SetX(GetX()-(GetSpeed()*elapsed));
			SetDirection(1);
		}
	}
	else if(target->GetCamo() == false && GetX() < GamePlayState::GetInstance()->GetCamX()+Game::GetInstance()->GetScreenWidth() && GetY() < GamePlayState::GetInstance()->GetCamY()+Game::GetInstance()->GetScreenHeight()
		&& GetX() > GamePlayState::GetInstance()->GetCamX() && GetY() > GamePlayState::GetInstance()->GetCamY() && GetCollided() == false && attackPlace == 4)
	{
		if(GetRect().top != target->GetRect().bottom-1 && target->GetRect().bottom-1 >= GetRect().top)
		{
			SetY(GetY()+(GetSpeed()*elapsed));
			SetDirection(2);
		}
		else if(GetRect().top != target->GetRect().bottom-1 && target->GetRect().bottom-1 <= GetRect().top)
		{
			SetY(GetY()-(GetSpeed()*elapsed));
			SetDirection(3);
		}

		else if(GetRect().right != target->GetRect().right && target->GetRect().right >= GetRect().right)
		{
			SetX(GetX()+(GetSpeed()*elapsed));
			SetDirection(0);
		}
		else if(GetRect().right != target->GetRect().right && target->GetRect().right <= GetRect().right)
		{
			SetX(GetX()-(GetSpeed()*elapsed));
			SetDirection(1);
		}
	}

	// Move
	if(BackAwayTimer > 0.0f)
	{
		if(GetDirection() == 0)
		{
			SetX(GetX()-(GetSpeed()*elapsed));
		}
		else if(GetDirection() == 1)
		{
			SetX(GetX()+(GetSpeed()*elapsed));
		}
		else if(GetDirection() == 2)
		{
			SetY(GetY()-(GetSpeed()*elapsed));
		}
		else if(GetDirection() == 3)
		{
			SetY(GetY()+(GetSpeed()*elapsed));
		}
		BackAwayTimer -= 1.0f*elapsed;
		if(BackAwayTimer <= 0.0f)
			attackPlace += 1;
	}

	// Update Animation
	for(int i = 0; i < 8; ++i)
	{
		TankAnimation[i].Update(elapsed);
	}
	if(CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(WalkSound) == false && target->GetRoomNum() == GetRoomNum())
		CSGD_XAudio2::GetInstance()->SFXPlaySound(WalkSound);

	// Attack
	if(inRange == true && GetAttackTimer() > 1.0f)
	{
		SpecialAttack(elapsed);
	}

	for(int i = 0; i < 4; ++i)
	{
		if(TankAnimation[i+4].IsPlaying() == false)
			inRange = false;
		else
			inRange = true;
	}

	// Check Wall Collision
	if(GetCollided() == false)
	{
		SetPrevX(GetX());
		SetPrevY(GetY());
	}
}

void TankBot::Render() 
{
	/*int camx = GamePlayState::GetInstance()->GetCamX();
	int camy = GamePlayState::GetInstance()->GetCamY();
	if( GetX() > camx + 800 || GetX() + GetWidth() < camx || GetY() + GetHeight() < camy || GetY() > camy + 600 )
	{
	return;
	}*/

	if(GetPlayer() != nullptr)
	{
		if(GetPlayer()->GetRoomNum() == GetRoomNum())
		{
			/*RECT collision = {(long)(GetRect().left-GamePlayState::GetInstance()->GetCamX()), (long)(GetRect().top-GamePlayState::GetInstance()->GetCamY()),
			(long)(GetRect().left-GamePlayState::GetInstance()->GetCamX()+GetWidth()), (long)(GetRect().top-GamePlayState::GetInstance()->GetCamY()+GetHeight())};
			CSGD_Direct3D::GetInstance()->DrawRect(collision,0,0,255);*/
			if(GetDirection() != -1 && inRange == false)
				TankAnimation[GetDirection()].Render((int)GetX()- GamePlayState::GetInstance()->GetCamX(),(int)GetY()- GamePlayState::GetInstance()->GetCamY(),1.0f,D3DCOLOR_ARGB(255,255,255,255),false);
			else if(GetDirection() != -1 && inRange == true)
				TankAnimation[GetDirection()+4].Render((int)GetX()- GamePlayState::GetInstance()->GetCamX(),(int)GetY()- GamePlayState::GetInstance()->GetCamY(),1.0f,D3DCOLOR_ARGB(255,255,255,255),false);
			else
				TankAnimation[0].Render((int)GetX()- GamePlayState::GetInstance()->GetCamX(),(int)GetY()- GamePlayState::GetInstance()->GetCamY(),1.0f,D3DCOLOR_ARGB(255,255,255,255),false);
		}
	}

	Enemy::Render();
}

bool TankBot::CheckCollision(IEntity* base) 
{
	if(Entity::CheckCollision(base) == true && base != this && base->GetType() != OBJ_WEAPON)
	{
		if(base->GetType() == OBJ_PLAYER)
		{
			SetX(GetPrevX()); 
			SetY(GetPrevY());

			if(base->GetRect().left <= GetRect().right)
				SetX(GetX()-1);
			else if(base->GetRect().right >= GetRect().left)
				SetX(GetX()+1);
			if(base->GetRect().bottom >= GetRect().top)
				SetY(GetY()+1);
			else if(base->GetRect().top <= GetRect().bottom)
				SetY(GetY()-1);

			SetCollided(true);
			inRange = true;
			return true;
		}
		if(base->GetType() == OBJ_ENEMY)
		{
			if(GetRect().left <= base->GetRect().left && GetRect().right <= base->GetRect().right && target->GetX() <= GetRect().left)
				SetX(GetPrevX());
			else if(GetRect().left >= base->GetRect().left && GetRect().right >= base->GetRect().right && target->GetX() <= GetRect().left)
			{
				BackAwayTimer = 1.0f;
			}
			else if(GetRect().left >= base->GetRect().left && GetRect().right >= base->GetRect().right && target->GetX() >= GetRect().right)
				SetX(GetPrevX());
			else if(GetRect().left <= base->GetRect().left && GetRect().right <= base->GetRect().right && target->GetX() >= GetRect().right)
			{
				BackAwayTimer = 1.0f;
			}

			if(GetRect().top >= base->GetRect().top && GetRect().bottom >= base->GetRect().bottom && target->GetY() <= GetRect().top)
				SetY(GetPrevY());
			else if(GetRect().top <= base->GetRect().top && GetRect().bottom <= base->GetRect().bottom && target->GetY() <= GetRect().top)
			{
				BackAwayTimer = 1.0f;
			}
			else if(GetRect().top >= base->GetRect().top && GetRect().bottom >= base->GetRect().bottom && target->GetY() >= GetRect().bottom)
				SetY(GetPrevY());
			else if(GetRect().top <= base->GetRect().top && GetRect().bottom <= base->GetRect().bottom && target->GetY() >= GetRect().bottom)
			{
				BackAwayTimer = 1.0f;
			}

			SetCollided(true);
			return true;
		}
		if(base->GetType() == OBJ_HAZARD)
		{
			BackAwayTimer = 1.0f;

			SetCollided(true);
			return true;
		}
		if(base->GetType() == OBJ_TILE && dynamic_cast<Tile*>(base)->GetSolid() == true)
		{
			BackAwayTimer = 1.0f;

			SetCollided(true);
			return true;
		}
	}
	else
		SetCollided(false);

	return false;
}

void TankBot::Attack(void)
{
	if(GetAttackTimer() > 1.0f && target)
	{
		SetAttackTimer(0.0f);
		CreateProjectileMessage* msg = new CreateProjectileMessage(ENEMY, this);
		MessageSystem::GetInstance()->SendMsg(msg);
		msg = nullptr;
		CSGD_XAudio2::GetInstance()->SFXPlaySound(FireSound);
	}
}

void TankBot::SpecialAttack(float elapsed) 
{
	CSGD_XAudio2::GetInstance()->SFXPlaySound(AttackSound);
	TankAnimation[GetDirection()+4].Play();

	/*if(elapsed == 0.0f)
	elapsed = 0.1f;*/

	const int x = GamePlayState::GetInstance()->GetCamX();
	const int y = GamePlayState::GetInstance()->GetCamY();

	if(GetX()-x > (224) && GetY()-y > (224)
		&& GetX()-x < (x-224) && GetY()-y < (y-224))
	{
		if(GetDirection() == 1)
		{
			target->SetX(GetX()-128);
			target->TakeDam(damage);
		}
		else if(GetDirection() == 0)
		{
			target->SetX(GetX()+128);
			target->TakeDam(damage);
		}
		else if(GetDirection() == 3)
		{
			target->SetY(GetY()-128);
			target->TakeDam(damage);
		}
		else if(GetDirection() == 2)
		{
			target->SetY(GetY()+128);
			target->TakeDam(damage);
		}
	}

		SetAttackTimer(0.0f);
		inRange = false;
}

void TankBot::HandleEvent(Event* thisEvent)
{
	if(thisEvent->GetParameter() != this)
		return;

	if(thisEvent->GetEventID() == "target_hit" && GetHealth() > 0)
	{
		void* tmpPtr = thisEvent->GetParameter2();
		float* tmp = (float*)(tmpPtr);
		SetHealth(GetHealth() - *tmp);

		delete tmp;

		damageEm->Burst();
	}
}

RECT TankBot::GetRect()
{
	RECT tmp = (GetDirection()!=-1 ? TankAnimation[GetDirection()].GetCollsionRect() : TankAnimation[0].GetCollsionRect());
	int width = tmp.right;
	int height = tmp.bottom;
	tmp.top += (long)(GetY() - (GetDirection()!=-1 ? TankAnimation[GetDirection()].GetAPoint().fY : TankAnimation[0].GetAPoint().fY) + height);
	tmp.bottom = height + tmp.top;
	tmp.left += (long)(GetX() - (GetDirection()!=-1 ? TankAnimation[GetDirection()].GetAPoint().fX : TankAnimation[0].GetAPoint().fX) + (width/2));
	tmp.right = width + tmp.left;
	return tmp;
}

void TankBot::SetAnimation(int id[8])
{
	for(int i = 0; i < 8; ++i)
	{
		TankAnimation[i] = *AnimationSystem::GetInstance()->GetAnimation(id[i]);
	}

	SetWidth(TankAnimation[0].GetCollsionRect().right);
	SetHeight(TankAnimation[0].GetCollsionRect().bottom);
}